package com.mischa.atc.tests;

import junit.framework.Assert;

import org.junit.Test;

import com.mischa.atc.Heading;

public class HeadingTest {
	private static final float WITHIN_PRECISION = 1E-4f;
	
	@Test
	public void DefaultHeadingIs360()
	{
		Heading north = new Heading();
		Assert.assertEquals(360f, north.get(), WITHIN_PRECISION);
	}
	
	@Test
	public void SetHeadingIsRetained()
	{
		Heading heading = new Heading();
		float value = 12.345f;
		heading.set(value);
		Assert.assertEquals(value, heading.get(), WITHIN_PRECISION);
	}
	
	@Test
	public void HeadingCanBeSetThroughConstructor()
	{
		float value = 12.345f;
		Heading heading = new Heading(value);		
		Assert.assertEquals(value, heading.get(), WITHIN_PRECISION);		
	}
	
	@Test
	public void HeadingIsCorrectlyConvertedToRadians()
	{		
		Assert.assertEquals(0f, 	   new Heading(0).getRadians(), WITHIN_PRECISION);
		Assert.assertEquals(Math.PI/6, new Heading(30).getRadians(), WITHIN_PRECISION);
		Assert.assertEquals(Math.PI/4, new Heading(45).getRadians(), WITHIN_PRECISION);
		Assert.assertEquals(Math.PI/2, new Heading(90).getRadians(), WITHIN_PRECISION);
		Assert.assertEquals(Math.PI,   new Heading(180).getRadians(), WITHIN_PRECISION);
	}
	
	@Test
	public void HeadingCanBeAddedToAndGivesValueInCorrectRangeBack()
	{
		Heading heading = new Heading();
		
		heading.add(10f);
		Assert.assertEquals(10f, heading.get(), WITHIN_PRECISION);
		
		heading.add(123.456f);
		Assert.assertEquals(133.456, heading.get(), WITHIN_PRECISION);
		
		heading.add(270);
		Assert.assertEquals(43.456, heading.get(), WITHIN_PRECISION);
	}
	
	@Test
	public void HeadingCanBeSubtractedFromByAddingNegativeAngle()
	{
		Heading heading = new Heading();
		
		heading.add(-10f);
		Assert.assertEquals(350f, heading.get(), WITHIN_PRECISION);
		
		heading.add(-123.456f);
		Assert.assertEquals(226.544, heading.get(), WITHIN_PRECISION);
	}
	
	@Test
	public void CanTestIfHeadingLiesBetweenTwoGivenHeadingsInClockwiseDirection()
	{
		Heading heading = new Heading(20);
		
		Assert.assertTrue(heading.liesBetweenCW(10, 30));
		Assert.assertTrue(heading.liesBetweenCW(0, 40));
		Assert.assertTrue(heading.liesBetweenCW(330, 310));
		Assert.assertTrue(heading.liesBetweenCW(360, 360));
	}
	
	@Test
	public void LiesBetweenIncludesUpperBoundaryButNotLower()
	{
		Assert.assertFalse(new Heading(20).liesBetweenCW(20, 30));
		Assert.assertTrue(new Heading(30).liesBetweenCW(20, 30));
		
		Assert.assertFalse(new Heading(0).liesBetweenCW(0, 180));
		Assert.assertTrue(new Heading(0).liesBetweenCW(180, 0));
	}
	
	@Test
	public void AnyHeadingLiesBetweenXAndXForAnyX()
	{
		float arbitrary = (float) (360 * Math.random());
		float heading = (float) (360 * Math.random());
		
		Assert.assertTrue(new Heading(heading).liesBetweenCW(arbitrary, arbitrary));
	}
	
	@Test
	public void ToStringGivesProperlyRoundedHeadingAsStringWithThreePositions()
	{
		Assert.assertEquals("360", new Heading(0).toString());
		Assert.assertEquals("008", new Heading(8).toString());
		Assert.assertEquals("090", new Heading(90).toString());
		Assert.assertEquals("123", new Heading(122.75f).toString());		
	}
	
	@Test
	public void DifferentObjectsRepresentingTheSameHeadingCompareAsEqual()
	{		
		Assert.assertTrue("Same headings do not compare equal", 
				new Heading(20).equals(new Heading(20)));
		Assert.assertTrue("Equivalent headings do not compare equal", 
				new Heading(90).equals(new Heading(-270)));
		Assert.assertTrue("Different north representations do not compare equal",
				new Heading(0).equals(new Heading(360)));
	}
}
